// Copyright (c) 2015-2019 The HomeKit ADK Contributors
//
// Licensed under the Apache License, Version 2.0 (the “License”);
// you may not use this file except in compliance with the License.
// See [CONTRIBUTORS.md] for the list of HomeKit ADK project authors.

#include "HAPPlatform.h"
#include "HAPCrypto.h"

#include <string.h>

// https://tools.ietf.org/html/rfc8032#section-7.1

static const uint8_t ed25519_sk[] = {
    0x4c, 0xcd, 0x08, 0x9b, 0x28, 0xff, 0x96, 0xda, 0x9d, 0xb6, 0xc3, 0x46, 0xec, 0x11, 0x4e, 0x0f,
    0x5b, 0x8a, 0x31, 0x9f, 0x35, 0xab, 0xa6, 0x24, 0xda, 0x8c, 0xf6, 0xed, 0x4f, 0xb8, 0xa6, 0xfb,
};

static const uint8_t ed25519_pk[] = {
    0x3d, 0x40, 0x17, 0xc3, 0xe8, 0x43, 0x89, 0x5a, 0x92, 0xb7, 0x0a, 0xa7, 0x4d, 0x1b, 0x7e, 0xbc,
    0x9c, 0x98, 0x2c, 0xcf, 0x2e, 0xc4, 0x96, 0x8c, 0xc0, 0xcd, 0x55, 0xf1, 0x2a, 0xf4, 0x66, 0x0c,
};

static const uint8_t ed25519_m[] = {
    0x72,
};

static const uint8_t ed25519_sig[] = {
    0x92, 0xa0, 0x09, 0xa9, 0xf0, 0xd4, 0xca, 0xb8, 0x72, 0x0e, 0x82, 0x0b, 0x5f, 0x64, 0x25, 0x40,
    0xa2, 0xb2, 0x7b, 0x54, 0x16, 0x50, 0x3f, 0x8f, 0xb3, 0x76, 0x22, 0x23, 0xeb, 0xdb, 0x69, 0xda,
    0x08, 0x5a, 0xc1, 0xe4, 0x3e, 0x15, 0x99, 0x6e, 0x45, 0x8f, 0x36, 0x13, 0xd0, 0xf1, 0x1d, 0x8c,
    0x38, 0x7b, 0x2e, 0xae, 0xb4, 0x30, 0x2a, 0xee, 0xb0, 0x0d, 0x29, 0x16, 0x12, 0xbb, 0x0c, 0x00,
};

#define test_ed25519(sk, pk, m, sig) \
    { \
        uint8_t p[ED25519_PUBLIC_KEY_BYTES]; \
        HAP_ed25519_public_key(p, sk); \
        HAPAssert(!memcmp(p, pk, ED25519_PUBLIC_KEY_BYTES)); \
        uint8_t s[ED25519_BYTES]; \
        HAP_ed25519_sign(s, m, sizeof m, sk, pk); \
        HAPAssert(!memcmp(s, sig, ED25519_BYTES)); \
        HAPAssert(!HAP_ed25519_verify(sig, m, sizeof m, pk)); \
        s[0] ^= 1; \
        HAPAssert(HAP_ed25519_verify(s, m, sizeof m, pk) == -1); \
        p[0] ^= 1; \
        HAPAssert(HAP_ed25519_verify(s, m, sizeof m, p) == -1); \
    }

// https://tools.ietf.org/html/rfc7748#section-5.2

static const uint8_t rfc7748_skey1[] = {
    0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a, 0xf5,
    0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x0d,
};

static const uint8_t rfc7748_pkey1[] = {
    0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c,
    0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x93,
};

static const uint8_t rfc7748_csec1[] = {
    0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, 0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, 0x73, 0xf8,
    0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57,
};

static const uint8_t rfc7748_alice_skey[] = {
    0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45,
    0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a,
};

static const uint8_t rfc7748_alice_pkey[] = {
    0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a,
    0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a,
};

#define test_X25519_1(sk, pk) \
    { \
        uint8_t p[X25519_BYTES]; \
        HAP_X25519_scalarmult_base(p, sk); \
        HAPAssert(!memcmp(p, pk, sizeof pk)); \
    }

#define test_X25519_2(sk, pk, cs) \
    { \
        uint8_t r[X25519_BYTES]; \
        HAP_X25519_scalarmult(r, sk, pk); \
        HAPAssert(!memcmp(r, cs, sizeof cs)); \
    }

// https://boringssl.googlesource.com/boringssl/+/2e2a226ac9201ac411a84b5e79ac3a7333d8e1c9/crypto/cipher_extra/test/chacha20_poly1305_tests.txt

static const uint8_t chacha20_poly1305_key[] = {
    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
};

static const uint8_t chacha20_poly1305_nonce[] = {
    0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
};

static const uint8_t chacha20_poly1305_aad[] = {
    0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
};

static const uint8_t chacha20_poly1305_pt[] =
        "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would "
        "be it.";

static const uint8_t chacha20_poly1305_tag[] = {
    0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91,
};

static const uint8_t chacha20_poly1305_ct[] = {
    0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, 0xa4, 0xad, 0xed,
    0x51, 0x29, 0x6e, 0x08, 0xfe, 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9,
    0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05,
    0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, 0x98, 0x03, 0xae, 0xe3,
    0x28, 0x09, 0x1b, 0x58, 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7,
    0xbc, 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, 0x61, 0x16,
};

#define test_chacha20_poly1305(key, nonce, pt, aad, tag, ct) \
    { \
        uint8_t t[CHACHA20_POLY1305_TAG_BYTES]; \
        uint8_t c[300]; \
        size_t pt_len = sizeof pt - 1; \
        HAP_chacha20_poly1305_encrypt_aad(t, c, pt, pt_len, aad, sizeof aad, nonce, sizeof nonce, key); \
        HAPAssert(!memcmp(c, ct, sizeof ct)); \
        HAPAssert(!memcmp(t, tag, sizeof tag)); \
        uint8_t m[300]; \
        int ret = HAP_chacha20_poly1305_decrypt_aad(tag, m, ct, sizeof ct, aad, sizeof aad, nonce, sizeof nonce, key); \
        HAPAssert(!ret); \
        HAPAssert(!memcmp(m, pt, pt_len)); \
        c[0] ^= 1; \
        ret = HAP_chacha20_poly1305_decrypt_aad(tag, m, c, sizeof ct, aad, sizeof aad, nonce, sizeof nonce, key); \
        HAPAssert(ret == -1); \
        t[0] ^= 1; \
        ret = HAP_chacha20_poly1305_decrypt_aad(t, m, ct, sizeof ct, aad, sizeof aad, nonce, sizeof nonce, key); \
        HAPAssert(ret == -1); \
    }

#define test_chacha20_poly1305_inc(key, nonce, pt, aad, tag, ct) \
    HAP_chacha20_poly1305_ctx ctx; \
    HAP_chacha20_poly1305_init(&ctx, nonce, sizeof nonce, key); \
    HAP_chacha20_poly1305_update_enc_aad(&ctx, aad, 1, nonce, sizeof nonce, key); \
    HAP_chacha20_poly1305_update_enc_aad(&ctx, aad + 1, sizeof aad - 1, nonce, sizeof nonce, key); \
    for (size_t i = 0; i < pt_len; ++i) { \
        HAP_chacha20_poly1305_update_enc(&ctx, c + i, pt + i, 1, nonce, sizeof nonce, key); \
    } \
    HAP_chacha20_poly1305_final_enc(&ctx, t); \
    HAPAssert(!memcmp(c, ct, sizeof ct)); \
    HAPAssert(!memcmp(t, tag, sizeof tag)); \
    HAP_chacha20_poly1305_init(&ctx, nonce, sizeof nonce, key); \
    HAP_chacha20_poly1305_update_dec_aad(&ctx, aad, sizeof aad, nonce, sizeof nonce, key); \
    for (int i = 0; i < sizeof ct; ++i) { \
        HAP_chacha20_poly1305_update_dec(&ctx, m + i, ct + i, 1, nonce, sizeof nonce, key); \
    } \
    ret = HAP_chacha20_poly1305_final_dec(&ctx, t); \
    HAPAssert(!ret); \
    HAPAssert(!memcmp(m, pt, sizeof ct)); \
    HAPAssert(!memcmp(t, tag, sizeof tag)); \
    }

// https://github.com/wolfSSL/wolfssl/issues/18#issuecomment-83941582

static const uint8_t srp_salt[] = { 0xBE, 0xB2, 0x53, 0x79, 0xD1, 0xA8, 0x58, 0x1E,
                                    0xB5, 0xA7, 0x27, 0x67, 0x3A, 0x24, 0x41, 0xEE };
static const uint8_t srp_user[] = "alice";
static const uint8_t srp_pass[] = "password123";
static const uint8_t srp_v[] = {
    0x9b, 0x5e, 0x06, 0x17, 0x01, 0xea, 0x7a, 0xeb, 0x39, 0xcf, 0x6e, 0x35, 0x19, 0x65, 0x5a, 0x85, 0x3c, 0xf9, 0x4c,
    0x75, 0xca, 0xf2, 0x55, 0x5e, 0xf1, 0xfa, 0xf7, 0x59, 0xbb, 0x79, 0xcb, 0x47, 0x70, 0x14, 0xe0, 0x4a, 0x88, 0xd6,
    0x8f, 0xfc, 0x05, 0x32, 0x38, 0x91, 0xd4, 0xc2, 0x05, 0xb8, 0xde, 0x81, 0xc2, 0xf2, 0x03, 0xd8, 0xfa, 0xd1, 0xb2,
    0x4d, 0x2c, 0x10, 0x97, 0x37, 0xf1, 0xbe, 0xbb, 0xd7, 0x1f, 0x91, 0x24, 0x47, 0xc4, 0xa0, 0x3c, 0x26, 0xb9, 0xfa,
    0xd8, 0xed, 0xb3, 0xe7, 0x80, 0x77, 0x8e, 0x30, 0x25, 0x29, 0xed, 0x1e, 0xe1, 0x38, 0xcc, 0xfc, 0x36, 0xd4, 0xba,
    0x31, 0x3c, 0xc4, 0x8b, 0x14, 0xea, 0x8c, 0x22, 0xa0, 0x18, 0x6b, 0x22, 0x2e, 0x65, 0x5f, 0x2d, 0xf5, 0x60, 0x3f,
    0xd7, 0x5d, 0xf7, 0x6b, 0x3b, 0x08, 0xff, 0x89, 0x50, 0x06, 0x9a, 0xdd, 0x03, 0xa7, 0x54, 0xee, 0x4a, 0xe8, 0x85,
    0x87, 0xcc, 0xe1, 0xbf, 0xde, 0x36, 0x79, 0x4d, 0xba, 0xe4, 0x59, 0x2b, 0x7b, 0x90, 0x4f, 0x44, 0x2b, 0x04, 0x1c,
    0xb1, 0x7a, 0xeb, 0xad, 0x1e, 0x3a, 0xeb, 0xe3, 0xcb, 0xe9, 0x9d, 0xe6, 0x5f, 0x4b, 0xb1, 0xfa, 0x00, 0xb0, 0xe7,
    0xaf, 0x06, 0x86, 0x3d, 0xb5, 0x3b, 0x02, 0x25, 0x4e, 0xc6, 0x6e, 0x78, 0x1e, 0x3b, 0x62, 0xa8, 0x21, 0x2c, 0x86,
    0xbe, 0xb0, 0xd5, 0x0b, 0x5b, 0xa6, 0xd0, 0xb4, 0x78, 0xd8, 0xc4, 0xe9, 0xbb, 0xce, 0xc2, 0x17, 0x65, 0x32, 0x6f,
    0xbd, 0x14, 0x05, 0x8d, 0x2b, 0xbd, 0xe2, 0xc3, 0x30, 0x45, 0xf0, 0x38, 0x73, 0xe5, 0x39, 0x48, 0xd7, 0x8b, 0x79,
    0x4f, 0x07, 0x90, 0xe4, 0x8c, 0x36, 0xae, 0xd6, 0xe8, 0x80, 0xf5, 0x57, 0x42, 0x7b, 0x2f, 0xc0, 0x6d, 0xb5, 0xe1,
    0xe2, 0xe1, 0xd7, 0xe6, 0x61, 0xac, 0x48, 0x2d, 0x18, 0xe5, 0x28, 0xd7, 0x29, 0x5e, 0xf7, 0x43, 0x72, 0x95, 0xff,
    0x1a, 0x72, 0xd4, 0x02, 0x77, 0x17, 0x13, 0xf1, 0x68, 0x76, 0xdd, 0x05, 0x0a, 0xe5, 0xb7, 0xad, 0x53, 0xcc, 0xb9,
    0x08, 0x55, 0xc9, 0x39, 0x56, 0x64, 0x83, 0x58, 0xad, 0xfd, 0x96, 0x64, 0x22, 0xf5, 0x24, 0x98, 0x73, 0x2d, 0x68,
    0xd1, 0xd7, 0xfb, 0xef, 0x10, 0xd7, 0x80, 0x34, 0xab, 0x8d, 0xcb, 0x6f, 0x0f, 0xcf, 0x88, 0x5c, 0xc2, 0xb2, 0xea,
    0x2c, 0x3e, 0x6a, 0xc8, 0x66, 0x09, 0xea, 0x05, 0x8a, 0x9d, 0xa8, 0xcc, 0x63, 0x53, 0x1d, 0xc9, 0x15, 0x41, 0x4d,
    0xf5, 0x68, 0xb0, 0x94, 0x82, 0xdd, 0xac, 0x19, 0x54, 0xde, 0xc7, 0xeb, 0x71, 0x4f, 0x6f, 0xf7, 0xd4, 0x4c, 0xd5,
    0xb8, 0x6f, 0x6b, 0xd1, 0x15, 0x81, 0x09, 0x30, 0x63, 0x7c, 0x01, 0xd0, 0xf6, 0x01, 0x3b, 0xc9, 0x74, 0x0f, 0xa2,
    0xc6, 0x33, 0xba, 0x89,
};
static const uint8_t srp_b[] = {
    0xe4, 0x87, 0xcb, 0x59, 0xd3, 0x1a, 0xc5, 0x50, 0x47, 0x1e, 0x81, 0xf0, 0x0f, 0x69, 0x28, 0xe0,
    0x1d, 0xda, 0x08, 0xe9, 0x74, 0xa0, 0x04, 0xf4, 0x9e, 0x61, 0xf5, 0xd1, 0x05, 0x28, 0x4d, 0x20,
};
static const uint8_t srp_A[] = {
    0xfa, 0xb6, 0xf5, 0xd2, 0x61, 0x5d, 0x1e, 0x32, 0x35, 0x12, 0xe7, 0x99, 0x1c, 0xc3, 0x74, 0x43, 0xf4, 0x87, 0xda,
    0x60, 0x4c, 0xa8, 0xc9, 0x23, 0x0f, 0xcb, 0x04, 0xe5, 0x41, 0xdc, 0xe6, 0x28, 0x0b, 0x27, 0xca, 0x46, 0x80, 0xb0,
    0x37, 0x4f, 0x17, 0x9d, 0xc3, 0xbd, 0xc7, 0x55, 0x3f, 0xe6, 0x24, 0x59, 0x79, 0x8c, 0x70, 0x1a, 0xd8, 0x64, 0xa9,
    0x13, 0x90, 0xa2, 0x8c, 0x93, 0xb6, 0x44, 0xad, 0xbf, 0x9c, 0x00, 0x74, 0x5b, 0x94, 0x2b, 0x79, 0xf9, 0x01, 0x2a,
    0x21, 0xb9, 0xb7, 0x87, 0x82, 0x31, 0x9d, 0x83, 0xa1, 0xf8, 0x36, 0x28, 0x66, 0xfb, 0xd6, 0xf4, 0x6b, 0xfc, 0x0d,
    0xdb, 0x2e, 0x1a, 0xb6, 0xe4, 0xb4, 0x5a, 0x99, 0x06, 0xb8, 0x2e, 0x37, 0xf0, 0x5d, 0x6f, 0x97, 0xf6, 0xa3, 0xeb,
    0x6e, 0x18, 0x20, 0x79, 0x75, 0x9c, 0x4f, 0x68, 0x47, 0x83, 0x7b, 0x62, 0x32, 0x1a, 0xc1, 0xb4, 0xfa, 0x68, 0x64,
    0x1f, 0xcb, 0x4b, 0xb9, 0x8d, 0xd6, 0x97, 0xa0, 0xc7, 0x36, 0x41, 0x38, 0x5f, 0x4b, 0xab, 0x25, 0xb7, 0x93, 0x58,
    0x4c, 0xc3, 0x9f, 0xc8, 0xd4, 0x8d, 0x4b, 0xd8, 0x67, 0xa9, 0xa3, 0xc1, 0x0f, 0x8e, 0xa1, 0x21, 0x70, 0x26, 0x8e,
    0x34, 0xfe, 0x3b, 0xbe, 0x6f, 0xf8, 0x99, 0x98, 0xd6, 0x0d, 0xa2, 0xf3, 0xe4, 0x28, 0x3c, 0xbe, 0xc1, 0x39, 0x3d,
    0x52, 0xaf, 0x72, 0x4a, 0x57, 0x23, 0x0c, 0x60, 0x4e, 0x9f, 0xbc, 0xe5, 0x83, 0xd7, 0x61, 0x3e, 0x6b, 0xff, 0xd6,
    0x75, 0x96, 0xad, 0x12, 0x1a, 0x87, 0x07, 0xee, 0xc4, 0x69, 0x44, 0x95, 0x70, 0x33, 0x68, 0x6a, 0x15, 0x5f, 0x64,
    0x4d, 0x5c, 0x58, 0x63, 0xb4, 0x8f, 0x61, 0xbd, 0xbf, 0x19, 0xa5, 0x3e, 0xab, 0x6d, 0xad, 0x0a, 0x18, 0x6b, 0x8c,
    0x15, 0x2e, 0x5f, 0x5d, 0x8c, 0xad, 0x4b, 0x0e, 0xf8, 0xaa, 0x4e, 0xa5, 0x00, 0x88, 0x34, 0xc3, 0xcd, 0x34, 0x2e,
    0x5e, 0x0f, 0x16, 0x7a, 0xd0, 0x45, 0x92, 0xcd, 0x8b, 0xd2, 0x79, 0x63, 0x93, 0x98, 0xef, 0x9e, 0x11, 0x4d, 0xfa,
    0xaa, 0xb9, 0x19, 0xe1, 0x4e, 0x85, 0x09, 0x89, 0x22, 0x4d, 0xdd, 0x98, 0x57, 0x6d, 0x79, 0x38, 0x5d, 0x22, 0x10,
    0x90, 0x2e, 0x9f, 0x9b, 0x1f, 0x2d, 0x86, 0xcf, 0xa4, 0x7e, 0xe2, 0x44, 0x63, 0x54, 0x65, 0xf7, 0x10, 0x58, 0x42,
    0x1a, 0x01, 0x84, 0xbe, 0x51, 0xdd, 0x10, 0xcc, 0x9d, 0x07, 0x9e, 0x6f, 0x16, 0x04, 0xe7, 0xaa, 0x9b, 0x7c, 0xf7,
    0x88, 0x3c, 0x7d, 0x4c, 0xe1, 0x2b, 0x06, 0xeb, 0xe1, 0x60, 0x81, 0xe2, 0x3f, 0x27, 0xa2, 0x31, 0xd1, 0x84, 0x32,
    0xd7, 0xd1, 0xbb, 0x55, 0xc2, 0x8a, 0xe2, 0x1f, 0xfc, 0xf0, 0x05, 0xf5, 0x75, 0x28, 0xd1, 0x5a, 0x88, 0x88, 0x1b,
    0xb3, 0xbb, 0xb7, 0xfe,
};
static const uint8_t srp_B[] = {
    0x40, 0xf5, 0x70, 0x88, 0xa4, 0x82, 0xd4, 0xc7, 0x73, 0x33, 0x84, 0xfe, 0x0d, 0x30, 0x1f, 0xdd, 0xca, 0x90, 0x80,
    0xad, 0x7d, 0x4f, 0x6f, 0xdf, 0x09, 0xa0, 0x10, 0x06, 0xc3, 0xcb, 0x6d, 0x56, 0x2e, 0x41, 0x63, 0x9a, 0xe8, 0xfa,
    0x21, 0xde, 0x3b, 0x5d, 0xba, 0x75, 0x85, 0xb2, 0x75, 0x58, 0x9b, 0xdb, 0x27, 0x98, 0x63, 0xc5, 0x62, 0x80, 0x7b,
    0x2b, 0x99, 0x08, 0x3c, 0xd1, 0x42, 0x9c, 0xdb, 0xe8, 0x9e, 0x25, 0xbf, 0xbd, 0x7e, 0x3c, 0xad, 0x31, 0x73, 0xb2,
    0xe3, 0xc5, 0xa0, 0xb1, 0x74, 0xda, 0x6d, 0x53, 0x91, 0xe6, 0xa0, 0x6e, 0x46, 0x5f, 0x03, 0x7a, 0x40, 0x06, 0x25,
    0x48, 0x39, 0xa5, 0x6b, 0xf7, 0x6d, 0xa8, 0x4b, 0x1c, 0x94, 0xe0, 0xae, 0x20, 0x85, 0x76, 0x15, 0x6f, 0xe5, 0xc1,
    0x40, 0xa4, 0xba, 0x4f, 0xfc, 0x9e, 0x38, 0xc3, 0xb0, 0x7b, 0x88, 0x84, 0x5f, 0xc6, 0xf7, 0xdd, 0xda, 0x93, 0x38,
    0x1f, 0xe0, 0xca, 0x60, 0x84, 0xc4, 0xcd, 0x2d, 0x33, 0x6e, 0x54, 0x51, 0xc4, 0x64, 0xcc, 0xb6, 0xec, 0x65, 0xe7,
    0xd1, 0x6e, 0x54, 0x8a, 0x27, 0x3e, 0x82, 0x62, 0x84, 0xaf, 0x25, 0x59, 0xb6, 0x26, 0x42, 0x74, 0x21, 0x59, 0x60,
    0xff, 0xf4, 0x7b, 0xdd, 0x63, 0xd3, 0xaf, 0xf0, 0x64, 0xd6, 0x13, 0x7a, 0xf7, 0x69, 0x66, 0x1c, 0x9d, 0x4f, 0xee,
    0x47, 0x38, 0x26, 0x03, 0xc8, 0x8e, 0xaa, 0x09, 0x80, 0x58, 0x1d, 0x07, 0x75, 0x84, 0x61, 0xb7, 0x77, 0xe4, 0x35,
    0x6d, 0xda, 0x58, 0x35, 0x19, 0x8b, 0x51, 0xfe, 0xea, 0x30, 0x8d, 0x70, 0xf7, 0x54, 0x50, 0xb7, 0x16, 0x75, 0xc0,
    0x8c, 0x7d, 0x83, 0x02, 0xfd, 0x75, 0x39, 0xdd, 0x1f, 0xf2, 0xa1, 0x1c, 0xb4, 0x25, 0x8a, 0xa7, 0x0d, 0x23, 0x44,
    0x36, 0xaa, 0x42, 0xb6, 0xa0, 0x61, 0x5f, 0x3f, 0x91, 0x5d, 0x55, 0xcc, 0x3b, 0x96, 0x6b, 0x27, 0x16, 0xb3, 0x6e,
    0x4d, 0x1a, 0x06, 0xce, 0x5e, 0x5d, 0x2e, 0xa3, 0xbe, 0xe5, 0xa1, 0x27, 0x0e, 0x87, 0x51, 0xda, 0x45, 0xb6, 0x0b,
    0x99, 0x7b, 0x0f, 0xfd, 0xb0, 0xf9, 0x96, 0x2f, 0xee, 0x4f, 0x03, 0xbe, 0xe7, 0x80, 0xba, 0x0a, 0x84, 0x5b, 0x1d,
    0x92, 0x71, 0x42, 0x17, 0x83, 0xae, 0x66, 0x01, 0xa6, 0x1e, 0xa2, 0xe3, 0x42, 0xe4, 0xf2, 0xe8, 0xbc, 0x93, 0x5a,
    0x40, 0x9e, 0xad, 0x19, 0xf2, 0x21, 0xbd, 0x1b, 0x74, 0xe2, 0x96, 0x4d, 0xd1, 0x9f, 0xc8, 0x45, 0xf6, 0x0e, 0xfc,
    0x09, 0x33, 0x8b, 0x60, 0xb6, 0xb2, 0x56, 0xd8, 0xca, 0xc8, 0x89, 0xcc, 0xa3, 0x06, 0xcc, 0x37, 0x0a, 0x0b, 0x18,
    0xc8, 0xb8, 0x86, 0xe9, 0x5d, 0xa0, 0xaf, 0x52, 0x35, 0xfe, 0xf4, 0x39, 0x30, 0x20, 0xd2, 0xb7, 0xf3, 0x05, 0x69,
    0x04, 0x75, 0x90, 0x42,
};
static const uint8_t srp_u[] = {
    0x03, 0xae, 0x5f, 0x3c, 0x3f, 0xa9, 0xef, 0xf1, 0xa5, 0x0d, 0x7d, 0xbb, 0x8d, 0x2f, 0x60, 0xa1,
    0xea, 0x66, 0xea, 0x71, 0x2d, 0x50, 0xae, 0x97, 0x6e, 0xe3, 0x46, 0x41, 0xa1, 0xcd, 0x0e, 0x51,
    0xc4, 0x68, 0x3d, 0xa3, 0x83, 0xe8, 0x59, 0x5d, 0x6c, 0xb5, 0x6a, 0x15, 0xd5, 0xfb, 0xc7, 0x54,
    0x3e, 0x07, 0xfb, 0xdd, 0xd3, 0x16, 0x21, 0x7e, 0x01, 0xa3, 0x91, 0xa1, 0x8e, 0xf0, 0x6d, 0xff,
};
static const uint8_t srp_S[] = {
    0xf1, 0x03, 0x6f, 0xec, 0xd0, 0x17, 0xc8, 0x23, 0x9c, 0x0d, 0x5a, 0xf7, 0xe0, 0xfc, 0xf0, 0xd4, 0x08, 0xb0, 0x09,
    0xe3, 0x64, 0x11, 0x61, 0x8a, 0x60, 0xb2, 0x3a, 0xab, 0xbf, 0xc3, 0x83, 0x39, 0x72, 0x68, 0x23, 0x12, 0x14, 0xba,
    0xac, 0xdc, 0x94, 0xca, 0x1c, 0x53, 0xf4, 0x42, 0xfb, 0x51, 0xc1, 0xb0, 0x27, 0xc3, 0x18, 0xae, 0x23, 0x8e, 0x16,
    0x41, 0x4d, 0x60, 0xd1, 0x88, 0x1b, 0x66, 0x48, 0x6a, 0xde, 0x10, 0xed, 0x02, 0xba, 0x33, 0xd0, 0x98, 0xf6, 0xce,
    0x9b, 0xcf, 0x1b, 0xb0, 0xc4, 0x6c, 0xa2, 0xc4, 0x7f, 0x2f, 0x17, 0x4c, 0x59, 0xa9, 0xc6, 0x1e, 0x25, 0x60, 0x89,
    0x9b, 0x83, 0xef, 0x61, 0x13, 0x1e, 0x6f, 0xb3, 0x0b, 0x71, 0x4f, 0x4e, 0x43, 0xb7, 0x35, 0xc9, 0xfe, 0x60, 0x80,
    0x47, 0x7c, 0x1b, 0x83, 0xe4, 0x09, 0x3e, 0x4d, 0x45, 0x6b, 0x9b, 0xca, 0x49, 0x2c, 0xf9, 0x33, 0x9d, 0x45, 0xbc,
    0x42, 0xe6, 0x7c, 0xe6, 0xc0, 0x2c, 0x24, 0x3e, 0x49, 0xf5, 0xda, 0x42, 0xa8, 0x69, 0xec, 0x85, 0x57, 0x80, 0xe8,
    0x42, 0x07, 0xb8, 0xa1, 0xea, 0x65, 0x01, 0xc4, 0x78, 0xaa, 0xc0, 0xdf, 0xd3, 0xd2, 0x26, 0x14, 0xf5, 0x31, 0xa0,
    0x0d, 0x82, 0x6b, 0x79, 0x54, 0xae, 0x8b, 0x14, 0xa9, 0x85, 0xa4, 0x29, 0x31, 0x5e, 0x6d, 0xd3, 0x66, 0x4c, 0xf4,
    0x71, 0x81, 0x49, 0x6a, 0x94, 0x32, 0x9c, 0xde, 0x80, 0x05, 0xca, 0xe6, 0x3c, 0x2f, 0x9c, 0xa4, 0x96, 0x9b, 0xfe,
    0x84, 0x00, 0x19, 0x24, 0x03, 0x7c, 0x44, 0x65, 0x59, 0xbd, 0xbb, 0x9d, 0xb9, 0xd4, 0xdd, 0x14, 0x2f, 0xbc, 0xd7,
    0x5e, 0xef, 0x2e, 0x16, 0x2c, 0x84, 0x30, 0x65, 0xd9, 0x9e, 0x8f, 0x05, 0x76, 0x2c, 0x4d, 0xb7, 0xab, 0xd9, 0xdb,
    0x20, 0x3d, 0x41, 0xac, 0x85, 0xa5, 0x8c, 0x05, 0xbd, 0x4e, 0x2d, 0xbf, 0x82, 0x2a, 0x93, 0x45, 0x23, 0xd5, 0x4e,
    0x06, 0x53, 0xd3, 0x76, 0xce, 0x8b, 0x56, 0xdc, 0xb4, 0x52, 0x7d, 0xdd, 0xc1, 0xb9, 0x94, 0xdc, 0x75, 0x09, 0x46,
    0x3a, 0x74, 0x68, 0xd7, 0xf0, 0x2b, 0x1b, 0xeb, 0x16, 0x85, 0x71, 0x4c, 0xe1, 0xdd, 0x1e, 0x71, 0x80, 0x8a, 0x13,
    0x7f, 0x78, 0x88, 0x47, 0xb7, 0xc6, 0xb7, 0xbf, 0xa1, 0x36, 0x44, 0x74, 0xb3, 0xb7, 0xe8, 0x94, 0x78, 0x95, 0x4f,
    0x6a, 0x8e, 0x68, 0xd4, 0x5b, 0x85, 0xa8, 0x8e, 0x4e, 0xbf, 0xec, 0x13, 0x36, 0x8e, 0xc0, 0x89, 0x1c, 0x3b, 0xc8,
    0x6c, 0xf5, 0x00, 0x97, 0x88, 0x01, 0x78, 0xd8, 0x61, 0x35, 0xe7, 0x28, 0x72, 0x34, 0x58, 0x53, 0x88, 0x58, 0xd7,
    0x15, 0xb7, 0xb2, 0x47, 0x40, 0x62, 0x22, 0xc1, 0x01, 0x9f, 0x53, 0x60, 0x3f, 0x01, 0x69, 0x52, 0xd4, 0x97, 0x10,
    0x08, 0x58, 0x82, 0x4c,
};
static const uint8_t srp_k[] = {
    0x5c, 0xbc, 0x21, 0x9d, 0xb0, 0x52, 0x13, 0x8e, 0xe1, 0x14, 0x8c, 0x71, 0xcd, 0x44, 0x98, 0x96,
    0x3d, 0x68, 0x25, 0x49, 0xce, 0x91, 0xca, 0x24, 0xf0, 0x98, 0x46, 0x8f, 0x06, 0x01, 0x5b, 0xeb,
    0x6a, 0xf2, 0x45, 0xc2, 0x09, 0x3f, 0x98, 0xc3, 0x65, 0x1b, 0xca, 0x83, 0xab, 0x8c, 0xab, 0x2b,
    0x58, 0x0b, 0xbf, 0x02, 0x18, 0x4f, 0xef, 0xdf, 0x26, 0x14, 0x2f, 0x73, 0xdf, 0x95, 0xac, 0x50,
};
static const uint8_t srp_m1[] = {
    0x5f, 0x7c, 0x14, 0xab, 0x57, 0xed, 0x0e, 0x94, 0xfd, 0x1d, 0x78, 0xc6, 0xb4, 0xdd, 0x09, 0xed,
    0x7e, 0x34, 0x0b, 0x7e, 0x05, 0xd4, 0x19, 0xa9, 0xfd, 0x76, 0x0f, 0x6b, 0x35, 0xe5, 0x23, 0xd1,
    0x31, 0x07, 0x77, 0xa1, 0xae, 0x1d, 0x28, 0x26, 0xf5, 0x96, 0xf3, 0xa8, 0x51, 0x16, 0xcc, 0x45,
    0x7c, 0x7c, 0x96, 0x4d, 0x4f, 0x44, 0xde, 0xd5, 0x55, 0x9d, 0xa8, 0x18, 0xc8, 0x8b, 0x61, 0x7f,
};
static const uint8_t srp_m2[] = {
    0x2f, 0xa0, 0xe8, 0x1f, 0x5c, 0xb7, 0x3b, 0x88, 0xfa, 0x09, 0x64, 0x27, 0x0f, 0x32, 0x1d, 0xd6,
    0x41, 0xf2, 0x22, 0x7a, 0x5d, 0x80, 0x5c, 0x40, 0xf1, 0xbf, 0xe9, 0x6a, 0xaf, 0x6a, 0x19, 0xff,
    0xce, 0x8e, 0x23, 0x28, 0x79, 0x65, 0xa3, 0x9e, 0xab, 0x9d, 0x5a, 0x02, 0x21, 0x5f, 0x89, 0xe1,
    0x28, 0x17, 0x7e, 0xd2, 0xc4, 0xf1, 0x03, 0xe6, 0x55, 0xa0, 0x45, 0x53, 0x1b, 0xcb, 0xf7, 0xad,
};

#include <stdio.h>

#define test_srp(salt, user, pass, v, A, b, B, u, S, k, m1, m2) \
    { \
        uint8_t _v[SRP_VERIFIER_BYTES]; \
        HAP_srp_verifier(_v, salt, user, sizeof user - 1, pass, sizeof pass - 1); \
        HAPAssert(!memcmp(_v, v, sizeof v)); \
        uint8_t _B[SRP_PUBLIC_KEY_BYTES]; \
        HAP_srp_public_key(_B, b, v); \
        HAPAssert(!memcmp(_B, B, sizeof B)); \
        uint8_t _u[SRP_SCRAMBLING_PARAMETER_BYTES]; \
        HAP_srp_scrambling_parameter(_u, A, B); \
        HAPAssert(!memcmp(_u, u, sizeof u)); \
        uint8_t _S[SRP_PREMASTER_SECRET_BYTES]; \
        HAP_srp_premaster_secret(_S, A, b, u, v); \
        HAPAssert(!memcmp(_S, S, sizeof S)); \
        uint8_t _k[SRP_SESSION_KEY_BYTES]; \
        HAP_srp_session_key(_k, S); \
        HAPAssert(!memcmp(_k, k, sizeof k)); \
        uint8_t _m1[SRP_PROOF_BYTES]; \
        HAP_srp_proof_m1(_m1, user, sizeof user - 1, salt, A, B, k); \
        HAPAssert(!memcmp(_m1, m1, sizeof m1)); \
        uint8_t _m2[SRP_PROOF_BYTES]; \
        HAP_srp_proof_m2(_m2, A, m1, k); \
        HAPAssert(!memcmp(_m2, m2, sizeof m2)); \
    }

// https://www.di-mgt.com.au/sha_testvectors.html

static const uint8_t sha_text[] = "abc";
static const uint8_t sha1_hash[] = {
    0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e,
    0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d,
};
static const uint8_t sha256_hash[] = { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40,
                                       0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17,
                                       0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad };
static const uint8_t sha512_hash[] = {
    0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31,
    0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a,
    0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
    0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f,
};

#define test_hash(algorithm, msg, hash) \
    { \
        uint8_t md[sizeof(hash)]; \
        algorithm(md, msg, sizeof msg - 1); \
        HAPAssert(!memcmp(md, hash, sizeof(hash))); \
    }

// https://www.kullo.net/blog/hkdf-sha-512-test-vectors

static const uint8_t hkdf_IKM[] = {
    0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
    0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
};
static const uint8_t hkdf_info[] = {
    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
};
static const uint8_t hkdf_salt[] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0b, 0x0c,
};
static const uint8_t hkdf_OKM[] = {
    0x83, 0x23, 0x90, 0x08, 0x6c, 0xda, 0x71, 0xfb, 0x47, 0x62, 0x5b, 0xb5, 0xce, 0xb1,
    0x68, 0xe4, 0xc8, 0xe2, 0x6a, 0x1a, 0x16, 0xed, 0x34, 0xd9, 0xfc, 0x7f, 0xe9, 0x2c,
    0x14, 0x81, 0x57, 0x93, 0x38, 0xda, 0x36, 0x2c, 0xb8, 0xd9, 0xf9, 0x25, 0xd7, 0xcb,
};

#define test_hkdf_sha512(key, salt, info, r) \
    { \
        uint8_t r_[sizeof(r)]; \
        HAP_hkdf_sha512(r_, sizeof r, key, sizeof key, salt, sizeof salt, info, sizeof info); \
        HAPAssert(!memcmp(r, r_, sizeof r)); \
    }

/* HAP_hmac_sha1 is only used by the WiFi code. */
#if HAP_IP
// https://tools.ietf.org/html/rfc2202

static const uint8_t rfc2202_key1[] = {
    0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
    0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
};
static const uint8_t rfc2202_in1[] = "Hi There";
static const uint8_t rfc2202_hmac1[] = {
    0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xe2, 0x8b,
    0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e, 0xf1, 0x46, 0xbe, 0x00,
};

#define HAP_hmac_sha1(h, k, k_len, in, in_len) HAP_hmac_sha1_aad(h, k, k_len, in, in_len, NULL, 0)

#define test_hmac_sha1(key, in, hmac) \
    { \
        uint8_t h[HMAC_SHA1_BYTES]; \
        HAP_hmac_sha1(h, key, sizeof key, in, sizeof in - 1); \
        HAPAssert(!memcmp(h, hmac, sizeof hmac)); \
    }
#endif

/* AES is only used by SRTP and WiFi */
#if HAP_IP
// https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf

static const uint8_t NIST_800_38A_key[16] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
                                              0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };

static const uint8_t NIST_800_38A_IV[16] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
                                             0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };

static const uint8_t NIST_800_38A_plaintext[] = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e,
                                                  0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03,
                                                  0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30,
                                                  0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19,
                                                  0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b,
                                                  0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 };

static const uint8_t NIST_800_38A_ciphertext[] = { 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68,
                                                   0x64, 0x99, 0x0d, 0xb6, 0xce, 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70,
                                                   0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff, 0x5a,
                                                   0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02,
                                                   0x0d, 0xb0, 0x3e, 0xab, 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03,
                                                   0xd1, 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee };

static const uint8_t AES_CTR_256_plaintext[] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
    0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
};

static const uint8_t AES_CTR_256_key[32] = {
    0xff, 0x7a, 0x61, 0x7c, 0xe6, 0x91, 0x48, 0xe4, 0xf1, 0x72, 0x6e, 0x2f, 0x43, 0x58, 0x1d, 0xe2,
    0xaa, 0x62, 0xd9, 0xf8, 0x05, 0x53, 0x2e, 0xdf, 0xf1, 0xee, 0xd6, 0x87, 0xfb, 0x54, 0x15, 0x3d,
};

static const uint8_t AES_CTR_256_IV[16] = {
    0x00, 0x1c, 0xc5, 0xb7, 0x51, 0xa5, 0x1d, 0x70, 0xa1, 0xc1, 0x11, 0x48, 0x00, 0x00, 0x00, 0x01,
};

static const uint8_t AES_CTR_256_ciphertext[] = {
    0xeb, 0x6c, 0x52, 0x82, 0x1d, 0x0b, 0xbb, 0xf7, 0xce, 0x75, 0x94, 0x46, 0x2a, 0xca, 0x4f, 0xaa, 0xb4, 0x07,
    0xdf, 0x86, 0x65, 0x69, 0xfd, 0x07, 0xf4, 0x8c, 0xc0, 0xb5, 0x83, 0xd6, 0x07, 0x1f, 0x1e, 0xc0, 0xe6, 0xb8,
};

#define test_aes_ctr(key, iv, plaintext, ciphertext) \
    { \
        HAP_aes_ctr_ctx ctx; \
        HAP_aes_ctr_init(&ctx, key, sizeof(key), iv); \
        uint8_t c[sizeof ciphertext], p[sizeof plaintext]; \
        HAP_aes_ctr_encrypt(&ctx, c, plaintext, sizeof plaintext); \
        HAP_aes_ctr_done(&ctx); \
        HAP_aes_ctr_init(&ctx, key, sizeof(key), iv); \
        HAP_aes_ctr_decrypt(&ctx, p, c, sizeof c); \
        HAP_aes_ctr_done(&ctx); \
        HAPAssert(!memcmp(c, ciphertext, sizeof c)); \
        HAPAssert(!memcmp(p, plaintext, sizeof p)); \
        HAP_aes_ctr_init(&ctx, key, sizeof(key), iv); \
        HAP_aes_ctr_encrypt(&ctx, c, plaintext, sizeof plaintext / 2); \
        HAP_aes_ctr_encrypt(&ctx, c + sizeof plaintext / 2, plaintext + sizeof plaintext / 2, sizeof plaintext / 2); \
        HAP_aes_ctr_done(&ctx); \
        HAPAssert(!memcmp(c, ciphertext, sizeof c)); \
    }
#endif

static void test_store_big_endian(uint32_t v) {
    uint8_t x[4];
    union {
        uint8_t x[4];
        uint32_t i;
    } u;
    HAP_store_bigendian(x, v);
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    v = __builtin_bswap32(v);
#endif
    u.i = v;
    HAPAssert(!memcmp(x, u.x, sizeof x));
}

// This trips an assert if BN_bn2bin is used in the OpenSSL backend because the
// verifier has to be padded to use the full SRP_VERIFIER_BYTES width.
static void test_bn_pad() {
    uint8_t v[SRP_VERIFIER_BYTES];
    uint8_t salt[SRP_SALT_BYTES];
    memset(salt, 0, sizeof salt);
    *(long*) salt = 217;
    HAP_srp_verifier(v, salt, (const uint8_t*) "", 0, (const uint8_t*) "", 0);
}

int main() {
    test_ed25519(ed25519_sk, ed25519_pk, ed25519_m, ed25519_sig);
    test_X25519_1(rfc7748_alice_skey, rfc7748_alice_pkey);
    test_X25519_2(rfc7748_skey1, rfc7748_pkey1, rfc7748_csec1);
    test_chacha20_poly1305(
            chacha20_poly1305_key,
            chacha20_poly1305_nonce,
            chacha20_poly1305_pt,
            chacha20_poly1305_aad,
            chacha20_poly1305_tag,
            chacha20_poly1305_ct);
#if HAP_IP
    test_chacha20_poly1305_inc(
            chacha20_poly1305_key,
            chacha20_poly1305_nonce,
            chacha20_poly1305_pt,
            chacha20_poly1305_aad,
            chacha20_poly1305_tag,
            chacha20_poly1305_ct);
#endif
    test_srp(srp_salt, srp_user, srp_pass, srp_v, srp_A, srp_b, srp_B, srp_u, srp_S, srp_k, srp_m1, srp_m2);
    test_hash(HAP_sha1, sha_text, sha1_hash);
    test_hash(HAP_sha256, sha_text, sha256_hash);
    test_hash(HAP_sha512, sha_text, sha512_hash);
    test_hkdf_sha512(hkdf_IKM, hkdf_salt, hkdf_info, hkdf_OKM);
#if HAP_IP
    test_hmac_sha1(rfc2202_key1, rfc2202_in1, rfc2202_hmac1);
    test_aes_ctr(NIST_800_38A_key, NIST_800_38A_IV, NIST_800_38A_plaintext, NIST_800_38A_ciphertext);
    test_aes_ctr(AES_CTR_256_key, AES_CTR_256_IV, AES_CTR_256_plaintext, AES_CTR_256_ciphertext);
#endif
    test_store_big_endian(0x12345678);
    test_bn_pad();
    return 0;
}
